﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace MintAnimation.Core
{

    // /// <summary>
    // /// 动画驱动事件
    // /// </summary>
    // /// <param name="timeScale">时间间隔 (s)</param>
    // /// <returns></returns>
    // public delegate void DriveUpdater(float timeScale);

    /// <summary>
    /// 动画驱动器
    /// </summary>
    public class MintDriveComponent : MonoBehaviour
    {

        private List<MintTween> _updateDrive      = null;
        private List<MintTween> _fixedUpdateDrive = null;
        private List<MintTween> _enumeratorDrive  = null;

        private int _updateCount;
        private int _fixedUpdateCount;
        private int _enumeratorCount;

        [Tooltip("时间缩放系数，改变此属性将影响所有使用改驱动器的动画速率")]
        public float TimeOffset = 1;

        internal void Init()
        {
            this._updateDrive      = new List<MintTween>();
            this._fixedUpdateDrive = new List<MintTween>();
            this._enumeratorDrive  = new List<MintTween>();
            this._updateCount      = 0;
            this._fixedUpdateCount = 0;
            this._enumeratorCount  = 0;
        }

        #region Public

        internal void AddDriveAction(MintTween driveAction, UpdaterTypeEnum driveEnum = UpdaterTypeEnum.Update)
        {
            switch (driveEnum)
            {
                case UpdaterTypeEnum.Update:
                    this._updateDrive.Add(driveAction);
                    break;
                case UpdaterTypeEnum.FixedUpdate:
                    this._fixedUpdateDrive.Add(driveAction);
                    break;
                case UpdaterTypeEnum.Coroutine:
                    this._enumeratorDrive.Add(driveAction);
                    break;
            }
        }

        internal void RemoveDriveAction(MintTween driveAction, UpdaterTypeEnum driveEnum = UpdaterTypeEnum.Update)
        {
            switch (driveEnum)
            {
                case UpdaterTypeEnum.Update:
                    this._updateDrive.Remove(driveAction);
                    break;
                case UpdaterTypeEnum.FixedUpdate:
                    this._fixedUpdateDrive.Remove(driveAction);
                    break;
                case UpdaterTypeEnum.Coroutine:
                    this._enumeratorDrive.Remove(driveAction);
                    break;
            }
        }

        internal void AddCount(UpdaterTypeEnum driveEnum)
        {
            switch (driveEnum)
            {
                case UpdaterTypeEnum.Update:
                    this._updateCount++;
                    break;
                case UpdaterTypeEnum.FixedUpdate:
                    this._fixedUpdateCount++;
                    break;
                case UpdaterTypeEnum.Coroutine:
                    this._enumeratorCount++;
                    break;
            }
        }

        internal void RemoveCount(UpdaterTypeEnum driveEnum)
        {
            switch (driveEnum)
            {
                case UpdaterTypeEnum.Update:
                    this._updateCount--;
                    break;
                case UpdaterTypeEnum.FixedUpdate:
                    this._fixedUpdateCount--;
                    break;
                case UpdaterTypeEnum.Coroutine:
                    this._enumeratorCount--;
                    break;
            }
        }

        #endregion

        #region Updater

        private void Update()      { this.ExecuteUpdater(this._updateCount,      this._updateDrive,      Time.deltaTime * this.TimeOffset); }
        private void FixedUpdate() { this.ExecuteUpdater(this._fixedUpdateCount, this._fixedUpdateDrive, Time.deltaTime * this.TimeOffset); }

        IEnumerator Updater()
        {
            while (true)
            {
                this.ExecuteUpdater(this._enumeratorCount, this._enumeratorDrive, Time.deltaTime * this.TimeOffset);
                yield return 0;
            }
        }

        private void ExecuteUpdater(int tweenLength, List<MintTween> tweens, float deltaTime)
        {
            if (tweenLength == 0)
                return;
            for (int i = 0; i < tweens.Count; i++)
            {
                var tween = tweens[i];
                if (!tween.IsPause)
                {
                    tween.UpdateTweenControl();
                    tween.OnLastControl(deltaTime);
                }
            }
        }

        #endregion

        private void OnEnable() { StartCoroutine(Updater()); }

        private void OnDisable() { StopAllCoroutines(); }

        private void OnDestroy()
        {
            for (int i = this._updateDrive.Count - 1; i >= 0; i--)
                this._updateDrive[i].Kill();
            for (int i = this._fixedUpdateDrive.Count - 1; i >= 0; i--)
                this._fixedUpdateDrive[i].Kill();
            for (int i = this._enumeratorDrive.Count - 1; i >= 0; i--)
                this._enumeratorDrive[i].Kill();
        }

    }
}